﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using SQLTouch.Service.DataContracts;

namespace SQLTouch.Service.Implementation.DAL
{
    public class SliceDAL : ISliceDAL
    {
        private interface IColumnBuilder
        {
            void Add(SqlDataReader reader);
            QueryResultColumnData Build();
        }

        private class ColumnBuilder<T> : IColumnBuilder
        {
            private readonly string name;
            private readonly int ordinal;
            private readonly List<T> values = new List<T>();

            public ColumnBuilder(string name, int ordinal)
            {
                this.name = name;
                this.ordinal = ordinal;
            }

            public void Add(SqlDataReader reader)
            {
                T value = reader.GetFieldValue<T>(ordinal);
                values.Add(value);
            }

            public QueryResultColumnData Build()
            {
                return new QueryResultColumnData<T>(name, values);
            }
        }

        public QueryResultData GetSlice(string connectionString, QueryData query)
        {
            string sql = query.GetSQL();

            List<IColumnBuilder> columns = new List<IColumnBuilder>();

            using (SqlConnection conn = new SqlConnection(connectionString))
            {
                conn.Open();
                using (SqlCommand cmd = new SqlCommand(sql, conn))
                {
                    cmd.CommandType = CommandType.Text;

                    using (SqlDataReader reader = cmd.ExecuteReader())
                    {
                        for (int i = 0; i < reader.VisibleFieldCount; i++)
                        {
                            string name = reader.GetName(i);
                            if (reader.GetFieldType(i) == typeof(int))
                            {
                                columns.Add(new ColumnBuilder<int>(name, i));
                            }
                            else if (reader.GetFieldType(i) == typeof(float))
                            {
                                columns.Add(new ColumnBuilder<float>(name, i));
                            }
                            else if (reader.GetFieldType(i) == typeof(double))
                            {
                                columns.Add(new ColumnBuilder<double>(name, i));
                            }
                            else if (reader.GetFieldType(i) == typeof(string))
                            {
                                columns.Add(new ColumnBuilder<string>(name, i));
                            }
                            else if (reader.GetFieldType(i) == typeof(DateTime))
                            {
                                columns.Add(new ColumnBuilder<DateTime>(name, i));
                            }
                        }

                        while (reader.Read())
                        {
                            foreach (IColumnBuilder column in columns)
                            {
                                column.Add(reader);
                            }
                        }
                    }
                }
            }

            return new QueryResultData(columns.Select(p => p.Build()));
        }
    }
}
